import { forEach, cloneDeepWith } from 'lodash-es'
/**
 *
 * @param component 需要注册的组件
 * @param alias 组件别名
 * @returns any
 */
export const withInstall = <T>(component: T, alias?: string) => {
  const comp = component as any
  comp.install = (app: any) => {
    app.component(comp.name || comp.displayName, component)
    if (alias) {
      app.config.globalProperties[alias] = component
    }
  }
  return component as T & Plugin
}

/**
 * @param str 需要转中划线的驼峰字符串
 * @returns 字符串下划线
 */
export const humpToUnderline = (str: string): string => {
  return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}

/**
 * @param str 需要转下划线的驼峰字符串
 * @returns 字符串下划线
 */
export const humpToUnderline1 = (str: string): string => {
  let result = ''
  for (let i = 0; i < str.length; i++) {
    const char = str[i]
    if (
      (i > 0 && char >= 'A' && char <= 'Z') ||
      (/[0-9]/.test(str[i - 1]) && /[a-zA-Z]/.test(char)) ||
      (/[a-zA-Z]/.test(str[i - 1]) && /[0-9]/.test(char))
    ) {
      result += '_'
    }
    result += char.toLowerCase()
  }
  return result
  // return str.replace(/([A-Z])/g, '_$1').toLowerCase()
}

/**
 * @param str 需要转驼峰的下划线字符串
 * @returns 字符串驼峰
 */
export const underlineToHump = (str: string): string => {
  if (!str) return ''
  return str.replace(/\-(\w)/g, (_, letter: string) => {
    return letter.toUpperCase()
  })
}

/**
 * 驼峰转横杠
 */
export const humpToDash = (str: string): string => {
  return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}

export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
  dom.style.setProperty(prop, val)
}

export const getCssVar = (prop: string, dom = document.documentElement) => {
  return getComputedStyle(dom).getPropertyValue(prop)
}

/**
 * 查找数组对象的某个下标
 * @param {Array} ary 查找的数组
 * @param {Functon} fn 判断的方法
 */
// eslint-disable-next-line
export const findIndex = <T = Recordable>(ary: Array<T>, fn: Fn): number => {
  if (ary.findIndex) {
    return ary.findIndex(fn)
  }
  let index = -1
  ary.some((item: T, i: number, ary: Array<T>) => {
    const ret: T = fn(item, i, ary)
    if (ret) {
      index = i
      return ret
    }
  })
  return index
}

export const trim = (str: string) => {
  return str.replace(/(^\s*)|(\s*$)/g, '')
}

/**
 * @param {Date | number | string} time 需要转换的时间
 * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
 */
export function formatTime(time: Date | number | string, fmt: string) {
  if (!time) return ''
  else {
    //处理文本时间戳无法转换的问题
    const date = new Date(typeof time === 'string' ? parseInt(time) : time)
    const o = {
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'H+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds(),
      'q+': Math.floor((date.getMonth() + 3) / 3),
      S: date.getMilliseconds()
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
    }
    for (const k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
        )
      }
    }
    return fmt
  }
}

/**
 * 生成随机字符串
 */
export function toAnyString() {
  const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
    const r: number = (Math.random() * 16) | 0
    const v: number = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString()
  })
  return str
}

/**
 * 首字母大写
 */
export function firstUpperCase(str: string) {
  return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
}

/**
 * 把对象转为formData
 */
export function objToFormData(obj: Recordable) {
  const formData = new FormData()
  Object.keys(obj).forEach((key) => {
    formData.append(key, obj[key])
  })
  return formData
}

export function getPageViewHeight(height: number) {
  return `calc(100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-content-padding) - var(--app-content-padding) - var(--el-card-padding) - var(--el-card-padding) - ${height}px)`
}
/**
 * 将数字转换为中文单位
 *
 * @param num 数字
 * @returns 对应的中文单位字符串
 */
export function getUnitByNumber(num: number) {
  if (num === 0) {
    return ''
  }
  const sign = num < 0 ? '负' : ''
  num = Math.abs(num)
  const units = [
    '',
    '十',
    '百',
    '千',
    '万',
    '十万',
    '百万',
    '千万',
    '亿',
    '十亿',
    '百亿',
    '千亿',
    '万亿',
    '十万亿',
    '百万亿',
    '千万亿',
    '兆',
    '十兆',
    '百兆',
    '千兆',
    '京',
    '十京',
    '百京',
    '千京',
    '垓',
    '十垓',
    '百垓',
    '千垓'
  ]
  let index = 0
  while (num >= 10 && index < units.length - 1) {
    num /= 10
    index++
  }
  return sign + units[index]
}

/**
 * 生成一个UUID字符串
 *
 * @returns 返回生成的UUID字符串
 */
export const generateUUID = (): string => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0
    const v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

/**
 * 创建一个生成雪花 ID 的函数。
 *
 * @param dataCenterId 数据中心 ID，必须在 0 到 MAX_DATACENTER_ID 之间
 * @param machineId 机器 ID，必须在 0 到 MAX_MACHINE_ID 之间
 * @param startTimeStamp 开始时间戳，默认为 1609459200000（2021-01-01 00:00:00 UTC）
 * @returns 生成雪花 ID 的函数
 * @throws 如果 dataCenterId 或 machineId 不在合法范围内，则抛出错误
 */
export function createSnowflakeGenerator(
  dataCenterId = 1,
  machineId = 1,
  startTimeStamp = 1609459200000
) {
  // 数据中心 ID 所占位数
  const DATACENTER_ID_BITS = 3
  // 机器 ID 所占位数
  const MACHINE_ID_BITS = 3
  // 序列号所占位数
  const SEQUENCE_BITS = 10

  // 数据中心 ID 最大值
  const MAX_DATACENTER_ID = -1 ^ (-1 << DATACENTER_ID_BITS)
  // 机器 ID 最大值
  const MAX_MACHINE_ID = -1 ^ (-1 << MACHINE_ID_BITS)
  // 序列号最大值
  const MAX_SEQUENCE = -1 ^ (-1 << SEQUENCE_BITS)

  // 机器 ID 向左移位数
  const MACHINE_ID_SHIFT = SEQUENCE_BITS
  // 数据中心 ID 向左移位数
  const DATACENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS
  // 时间戳向左移位数
  const TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS

  // 检查数据中心 ID 和机器 ID 是否合法
  if (dataCenterId > MAX_DATACENTER_ID || dataCenterId < 0) {
    throw new Error(`Data center ID must be between 0 and ${MAX_DATACENTER_ID}`)
  }
  if (machineId > MAX_MACHINE_ID || machineId < 0) {
    throw new Error(`Machine ID must be between 0 and ${MAX_MACHINE_ID}`)
  }

  let sequence = 0
  let lastTimestamp = -1

  // 获取当前时间戳
  function getCurrentTimestamp() {
    return Date.now()
  }

  // 等待下一毫秒
  function waitNextMillis(lastTimestampValue: number) {
    let timestamp = getCurrentTimestamp()
    while (timestamp <= lastTimestampValue) {
      timestamp = getCurrentTimestamp()
    }
    return timestamp
  }

  // 生成雪花 ID
  return function nextId() {
    let timestamp = getCurrentTimestamp()

    if (timestamp < lastTimestamp) {
      throw new Error(
        'Clock moved backwards. Refusing to generate id for ' +
          (lastTimestamp - timestamp) +
          ' milliseconds'
      )
    }

    if (timestamp === lastTimestamp) {
      sequence = (sequence + 1) & MAX_SEQUENCE
      if (sequence === 0) {
        timestamp = waitNextMillis(lastTimestamp)
      }
    } else {
      sequence = 0
    }

    lastTimestamp = timestamp

    let id =
      ((timestamp - startTimeStamp) << TIMESTAMP_LEFT_SHIFT) |
      (dataCenterId << DATACENTER_ID_SHIFT) |
      (machineId << MACHINE_ID_SHIFT) |
      sequence

    // 确保生成的 ID 为正数
    if (id < 0) {
      id = id >>> 0 // 无符号右移 0 位，将负数转换为正数
    }

    return id
  }
}

export function sleep(ms: number, callback?: Function) {
  return new Promise((resolve) =>
    setTimeout(async () => {
      await (callback == null ? void 0 : callback())
      resolve(true)
    }, ms)
  )
}
